From 33db3abdadd6687eb16305014c70654e03168fe5 Mon Sep 17 00:00:00 2001 From: GrailFinder Date: Sun, 17 Mar 2024 13:13:01 +0300 Subject: init --- .gitignore | 3 ++ Makefile | 36 +++++++++++++++++++++++ README.md | 1 + cmd/root.go | 46 +++++++++++++++++++++++++++++ cmd/start.go | 37 +++++++++++++++++++++++ config/config.go | 43 +++++++++++++++++++++++++++ go.mod | 31 ++++++++++++++++++++ go.sum | 75 +++++++++++++++++++++++++++++++++++++++++++++++ internal/handlers/main.go | 36 +++++++++++++++++++++++ internal/server/main.go | 60 +++++++++++++++++++++++++++++++++++++ internal/server/router.go | 23 +++++++++++++++ internal/service/main.go | 0 main.go | 14 +++++++++ 13 files changed, 405 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 cmd/root.go create mode 100644 cmd/start.go create mode 100644 config/config.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/handlers/main.go create mode 100644 internal/server/main.go create mode 100644 internal/server/router.go create mode 100644 internal/service/main.go create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9339e73 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +secrethitler +config.yml +apjournal diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e8d3207 --- /dev/null +++ b/Makefile @@ -0,0 +1,36 @@ +.PHONY: all init deps install test lint run stop + +run: + # templ generate + go build + ./secrethitler start + +init: + go mod init + +# install all dependencies used by the application +deps: + go clean -modcache + go mod download + +# install the application in the Go bin/ folder +install: + go install ./... + +test: + go test ./... + +lint: + golangci-lint run --config .golangci.yml + +gen: + go generate ./... + +build-container: + docker build -t secretH:master . + +stop-container: + docker rm -f secretH 2>/dev/null && echo "old container removed" + +run-container: stop-container + docker run --name=secretH -v $(CURDIR)/store.json:/root/store.json -p 0.0.0.0:8087:8087 -d secretH:master diff --git a/README.md b/README.md new file mode 100644 index 0000000..135609a --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# Goserver implementation for tabletop game named Secret Hitler diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..9e87b5b --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,46 @@ +package cmd + +import ( + "log" + + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// LogLevel Flag +var LogLevel = "info" +var LogFormat = "json" +var cfgFile string +var rootCmd = &cobra.Command{ + Use: "apjournal", + Short: "apjournal", +} + +func init() { + cobra.OnInitialize(initConfig) + rootCmd.PersistentFlags().StringVar(&cfgFile, + "config", "", "config file (default is ./config.yml)") + viper.SetConfigName("config") + viper.AddConfigPath(".") // First try to load the config from the current directory + viper.AddConfigPath("$HOME") // Then try to load it from the HOME directory + viper.AddConfigPath("/etc/apjournal/") // As a last resort try to load it from the /etc/ +} + +func initConfig() { + if cfgFile != "" { + // Use config file from the flag. + viper.SetConfigFile(cfgFile) + } + viper.SetEnvPrefix("CFG") + viper.AutomaticEnv() + if err := viper.ReadInConfig(); err != nil { + log.Fatal("Can't read configuration file", "error", err) + } +} + +// Execute the commands +func Execute() { + if err := rootCmd.Execute(); err != nil { + log.Fatal("failed to execute", "error", err) + } +} diff --git a/cmd/start.go b/cmd/start.go new file mode 100644 index 0000000..00872aa --- /dev/null +++ b/cmd/start.go @@ -0,0 +1,37 @@ +package cmd + +import ( + "os" + "apjournal/config" + "apjournal/internal/server" + + "log/slog" + + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func init() { + rootCmd.AddCommand(startCmd) +} + +var startCmd = &cobra.Command{ + Use: "start", + Short: "Start data server", + Long: `Start data server`, + Run: func(cmd *cobra.Command, args []string) { + log := slog.New(slog.NewJSONHandler(os.Stdout, nil)) + // load server configuration from server + log.Debug("Loading server configuration") + if viper.ConfigFileUsed() != "" { + log.Debug("Configuration file loaded", "section", "init", + "path", viper.ConfigFileUsed()) + } + cfg := config.LoadConfig(viper.GetViper()) + + srv := server.NewServer(cfg, log) + // listen for new messages + log.Info("Listening for incoming events") + srv.Listen() + }, +} diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..135df95 --- /dev/null +++ b/config/config.go @@ -0,0 +1,43 @@ +package config + +import ( + "log/slog" + "os" + + "github.com/spf13/viper" +) + +type Config struct { + ServerConfig ServerConfig `mapstructure:"SERVICE"` + BaseURL string `mapstructure:"BASE_URL"` + SessionLifetime int `mapstructure:"SESSION_LIFETIME_SECONDS"` +} + +type ServerConfig struct { + Host string `mapstructure:"HOST"` + Port string `mapstructure:"PORT"` +} + +// LoadConfig Load server configuration from the yaml file +func LoadConfig(viperConf *viper.Viper) Config { + logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) + var config Config + + err := viperConf.Unmarshal(&config) + if err != nil { + logger.Error("Unable to decode configuration file", "error", err) + } + return config +} + +// OpenConfig open config file +func OpenConfig() { + logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) + viper.SetConfigType("yml") + viper.SetConfigName("config") + viper.SetEnvPrefix("CFG") + err := viper.ReadInConfig() // Find and read the config file + if err != nil { // Handle errors reading the config file + logger.Error("Unable to read configuration file", "error", err) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..71dd35f --- /dev/null +++ b/go.mod @@ -0,0 +1,31 @@ +module apjournal + +go 1.22.1 + +require ( + github.com/spf13/cobra v1.8.0 + github.com/spf13/viper v1.18.2 +) + +require ( + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..b6a7dcc --- /dev/null +++ b/go.sum @@ -0,0 +1,75 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/handlers/main.go b/internal/handlers/main.go new file mode 100644 index 0000000..3b551f1 --- /dev/null +++ b/internal/handlers/main.go @@ -0,0 +1,36 @@ +package handlers + +import ( + "log/slog" + "net/http" + "os" + "apjournal/config" +) + +// Handlers structure +type Handlers struct { + cfg config.Config + // s *service.Service + log *slog.Logger +} + +// NewHandlers constructor +func NewHandlers( + // cfg config.Config, s *service.Service, l *slog.Logger, + cfg config.Config, l *slog.Logger, +) *Handlers { + if l == nil { + l = slog.New(slog.NewJSONHandler(os.Stdout, nil)) + } + h := &Handlers{ + cfg: cfg, + // s: s, + log: l, + } + return h +} + +func (h *Handlers) Ping(w http.ResponseWriter, r *http.Request) { + h.log.Info("got ping request") + w.Write([]byte("pong")) +} diff --git a/internal/server/main.go b/internal/server/main.go new file mode 100644 index 0000000..45f3d41 --- /dev/null +++ b/internal/server/main.go @@ -0,0 +1,60 @@ +package server + +import ( + "apjournal/config" + "apjournal/internal/handlers" + + "context" + "log/slog" + "os" + "os/signal" + "syscall" +) + +// Server interface +type Server interface { + Listen() +} + +type server struct { + config config.Config + actions *handlers.Handlers + ctx context.Context + close context.CancelFunc +} + +func (srv *server) stopOnSignal(close context.CancelFunc) { + // listen for termination signals + sigc := make(chan os.Signal, 1) + signal.Notify(sigc, os.Interrupt, syscall.SIGINT) + signal.Notify(sigc, os.Interrupt, syscall.SIGTERM) + sig := <-sigc + + log := slog.New(slog.NewJSONHandler(os.Stdout, nil)) + log.Info("Shutting down services", + "section", "server", + "app_event", "terminate", + "signal", sig.String()) + close() + os.Exit(0) +} + +func NewServer(cfg config.Config, log *slog.Logger) Server { + ctx, close := context.WithCancel(context.Background()) + // s := service.NewService(ctx, cfg, store.MemCache) + actions := handlers.NewHandlers(cfg, log) + + return &server{ + config: cfg, + actions: actions, + ctx: ctx, + close: close, + } +} + +// Listen for new events that affect the market and process them +func (srv *server) Listen() { + // start the http server + go srv.ListenToRequests() + srv.stopOnSignal(srv.close) +} diff --git a/internal/server/router.go b/internal/server/router.go new file mode 100644 index 0000000..ed33c19 --- /dev/null +++ b/internal/server/router.go @@ -0,0 +1,23 @@ +package server + +import ( + "fmt" + "net/http" + "time" +) + +func (srv *server) ListenToRequests() { + h := srv.actions + mux := http.NewServeMux() + server := &http.Server{ + Addr: "localhost:9000", + Handler: mux, + ReadTimeout: time.Second * 5, + WriteTimeout: time.Second * 5, + } + + mux.HandleFunc("/ping", h.Ping) + + fmt.Printf("Listening on %v\n", server.Addr) + server.ListenAndServe() +} diff --git a/internal/service/main.go b/internal/service/main.go new file mode 100644 index 0000000..e69de29 diff --git a/main.go b/main.go new file mode 100644 index 0000000..10c7fee --- /dev/null +++ b/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "runtime" + "apjournal/cmd" +) + +func init() { + runtime.GOMAXPROCS(runtime.NumCPU()) +} + +func main() { + cmd.Execute() +} -- cgit v1.2.3