diff options
| author | Mel <einebeere@gmail.com> | 2024-12-29 18:06:59 +0100 |
|---|---|---|
| committer | Mel <einebeere@gmail.com> | 2024-12-29 18:06:59 +0100 |
| commit | 18c168e2debe952e932e360ec3dbc9c58ad3cd3f (patch) | |
| tree | 2d7a118a18e5edc17b06fe7a313811711c45ad50 | |
| parent | 5025fab41ac37665ad35967f1f03c16588461605 (diff) | |
| download | specimen-18c168e2debe952e932e360ec3dbc9c58ad3cd3f.tar.zst specimen-18c168e2debe952e932e360ec3dbc9c58ad3cd3f.zip | |
Read configuration from flags and reply with configured name step-1
Signed-off-by: Mel <einebeere@gmail.com>
| -rw-r--r-- | Taskfile.yml | 3 | ||||
| -rw-r--r-- | application/cmd/specimen/cfg/config.go | 65 | ||||
| -rw-r--r-- | application/cmd/specimen/main.go | 15 | ||||
| -rw-r--r-- | application/pkg/specimen/handler.go | 34 | ||||
| -rw-r--r-- | application/pkg/specimen/server.go | 14 | ||||
| -rw-r--r-- | example-name | 1 |
6 files changed, 118 insertions, 14 deletions
diff --git a/Taskfile.yml b/Taskfile.yml index ac379ae..a8ce472 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -9,7 +9,6 @@ tasks: run: desc: "Run specimen application binary." - dir: application deps: [build] cmds: - - build/specimen + - application/build/specimen {{.CLI_ARGS}} diff --git a/application/cmd/specimen/cfg/config.go b/application/cmd/specimen/cfg/config.go new file mode 100644 index 0000000..713ad96 --- /dev/null +++ b/application/cmd/specimen/cfg/config.go @@ -0,0 +1,65 @@ +package cfg + +import ( + "errors" + "flag" + "fmt" + "os" +) + +type Config struct { + Port int + Address string + + // since the server will be restarted when the name file changes, + // we can read the file directly after parsing the arguments, + // and pass the name to the server. no need to pass the path to the server. + Name string +} + +func ParseFromArguments() (Config, error) { + c := Config{} + var namePath string + + defineFlags(&c, &namePath) + flag.Parse() + + if err := validateAndSet(&c, namePath); err != nil { + return Config{}, err + } + + return c, nil +} + +func defineFlags(c *Config, namePath *string) { + flag.IntVar(&c.Port, "port", 4444, "port to listen on") + flag.StringVar(&c.Address, "address", "127.0.0.1", "address to listen on") + flag.StringVar(namePath, "name", "", "path to the name file") +} + +func validateAndSet(c *Config, namePath string) error { + if c.Port < 1 || c.Port > 65535 { + return errors.New("port is out of range") + } + + if namePath == "" { + return errors.New("name file path is required") + } + + file, err := os.Open(namePath) + if err != nil { + return fmt.Errorf("failed to open the name file. %w", err) + } + + name := make([]byte, 1024) + n, err := file.Read(name) + if err != nil { + return fmt.Errorf("failed to read the name file. %w", err) + } + + fmt.Printf("read %d bytes from the name file\n", n) + fmt.Printf("name: %s\n", string(name[:n])) + + c.Name = string(name[:n]) + return nil +} diff --git a/application/cmd/specimen/main.go b/application/cmd/specimen/main.go index cf7ff36..9b3cc03 100644 --- a/application/cmd/specimen/main.go +++ b/application/cmd/specimen/main.go @@ -2,11 +2,13 @@ package main import ( "context" + "flag" "log/slog" "os" "os/signal" "time" + "git.rnrd.eu/specimen/cmd/specimen/cfg" "git.rnrd.eu/specimen/pkg/specimen" "git.rnrd.eu/specimen/pkg/util" ) @@ -17,13 +19,20 @@ func main() { ctx := context.Background() logger := createLogger() - if err := start(ctx, logger); err != nil { + config, err := cfg.ParseFromArguments() + if err != nil { + logger.Error("argument error!", util.SlogErr(err)) + flag.Usage() + os.Exit(1) + } + + if err := start(ctx, logger, config); err != nil { logger.Error("failed to start the specimen application :(", util.SlogErr(err)) os.Exit(1) } } -func start(ctx context.Context, logger *slog.Logger) error { +func start(ctx context.Context, logger *slog.Logger, config cfg.Config) error { // listen for SIGINT (or others on other systems, but who cares about those.. :3) ctx, cancel := signal.NotifyContext(ctx, os.Interrupt) defer cancel() @@ -31,7 +40,7 @@ func start(ctx context.Context, logger *slog.Logger) error { logger.Info("starting the specimen application!", slog.String("version", version)) // start the specimen server! - server := specimen.NewServer(logger) + server := specimen.NewServer(logger, config) go server.Start(ctx) // listen for signals to gracefully shutdown the server diff --git a/application/pkg/specimen/handler.go b/application/pkg/specimen/handler.go index 05a56ec..6d4e733 100644 --- a/application/pkg/specimen/handler.go +++ b/application/pkg/specimen/handler.go @@ -1,19 +1,47 @@ package specimen import ( + "fmt" "log/slog" "net/http" ) type requestHandler struct { logger *slog.Logger + name string } -func newRequestHandler(logger *slog.Logger) *requestHandler { - return &requestHandler{logger: logger} +func newRequestHandler(logger *slog.Logger, name string) *requestHandler { + return &requestHandler{logger: logger, name: name} } func (h *requestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - h.logger.Info("received a request!", slog.String("method", r.Method), slog.String("url", r.URL.String())) + // NOTE: we could also write some logger middleware, + // but that probably would be overkill for this... + logger := h.logger.With(requestLogAttrs(r)) + logger.Info("incoming request.") + + reply := h.message() + + w.Header().Set("Content-Type", "text/plain") w.WriteHeader(http.StatusOK) + if _, err := w.Write([]byte(reply)); err != nil { + logger.Error("failed to write the response.", slog.Any("error", err)) + return + } + + logger.Info("request successfully handled.") +} + +func (h *requestHandler) message() string { + return fmt.Sprintf("hello %s", h.name) +} + +func requestLogAttrs(r *http.Request) slog.Attr { + return slog.Group( + "request", + slog.String("method", r.Method), + slog.String("url", r.URL.String()), + slog.String("remote_addr", r.RemoteAddr), + ) } diff --git a/application/pkg/specimen/server.go b/application/pkg/specimen/server.go index cccf6e2..2a222a3 100644 --- a/application/pkg/specimen/server.go +++ b/application/pkg/specimen/server.go @@ -6,23 +6,25 @@ import ( "log/slog" "net/http" "time" -) -const port = 4444 + "git.rnrd.eu/specimen/cmd/specimen/cfg" +) type Server struct { logger *slog.Logger + config cfg.Config server *http.Server handler *requestHandler } -func NewServer(logger *slog.Logger) *Server { - handler := newRequestHandler(logger) +func NewServer(logger *slog.Logger, config cfg.Config) *Server { + handler := newRequestHandler(logger, config.Name) return &Server{ logger: logger, + config: config, server: &http.Server{ - Addr: fmt.Sprintf(":%d", port), + Addr: fmt.Sprintf("%s:%d", config.Address, config.Port), Handler: handler, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, @@ -31,7 +33,7 @@ func NewServer(logger *slog.Logger) *Server { } func (s *Server) Start(ctx context.Context) { - s.logger.Info("listening for incoming connections...") + s.logger.Info("listening for incoming connections...", slog.String("address", s.server.Addr)) err := s.server.ListenAndServe() switch err { diff --git a/example-name b/example-name new file mode 100644 index 0000000..65b30b3 --- /dev/null +++ b/example-name @@ -0,0 +1 @@ +philip \ No newline at end of file |
