aboutsummaryrefslogtreecommitdiffstats
path: root/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'main.go')
-rw-r--r--main.go121
1 files changed, 121 insertions, 0 deletions
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..6404940
--- /dev/null
+++ b/main.go
@@ -0,0 +1,121 @@
+package gopkgserver
+
+import (
+ "context"
+ _ "embed"
+ "errors"
+ "flag"
+ "fmt"
+ "io"
+ "log/slog"
+ "net"
+ "net/http"
+ "os"
+
+ "github.com/pelletier/go-toml/v2"
+
+ "go-pkg-server/logging"
+ "go-pkg-server/logging/handler"
+ "go-pkg-server/repo"
+)
+
+type ServerConfig struct {
+ Proto string `toml:"proto"`
+ Address string `toml:"address"`
+}
+
+type Config struct {
+ Server ServerConfig `toml:"server"`
+ Log logging.Config `toml:"log"`
+ Repos map[string]repo.Repo `toml:"repo"`
+}
+
+func Run(ctx context.Context, fs *flag.FlagSet, args []string) error {
+ var cfgFile string
+ fs.StringVar(&cfgFile, "config", "config.toml", "Path to config file")
+ fs.Parse(args)
+
+ cfg, err := LoadConfig(cfgFile)
+ if err != nil {
+ return err
+ }
+
+ logger := logging.SetupLogger(cfg.Log)
+ ctx = logging.WithLogger(ctx, logger)
+
+ h, err := repo.New(cfg.Repos)
+ if err != nil {
+ return fmt.Errorf(": %v", err)
+ }
+
+ mux := http.NewServeMux()
+ mux.Handle("GET /robots.txt", Robot())
+ mux.Handle("GET /", h)
+
+ return RunServer(ctx, handler.New(mux), cfg.Server)
+}
+
+func LoadConfig(cfgFile string) (Config, error) {
+ data, err := os.ReadFile(cfgFile)
+ if err != nil {
+ return Config{}, fmt.Errorf("read config: %w", err)
+ }
+
+ var cfg Config
+ if err := toml.Unmarshal(data, &cfg); err != nil {
+ return Config{}, fmt.Errorf("parse config: %w", err)
+ }
+
+ if cfg.Server.Proto == "" {
+ cfg.Server.Proto = "tcp"
+ }
+
+ return cfg, nil
+}
+
+func RunServer(ctx context.Context, mux http.Handler, config ServerConfig) error {
+ logger := logging.FromContext(ctx)
+
+ srv := &http.Server{
+ Handler: mux,
+ BaseContext: func(l net.Listener) context.Context {
+ logger := logger.With("address", l.Addr())
+ ctx = logging.WithLogger(ctx, logger)
+ return ctx
+ },
+ ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError),
+ }
+
+ ln, err := net.Listen(config.Proto, config.Address)
+ if err != nil {
+ return err
+ }
+
+ logger.Log(ctx, slog.LevelError, "Server Started on", "address", ln.Addr())
+
+ go func() {
+ <-ctx.Done()
+ shutdownCtx := context.Background()
+ // We received an interrupt signal, shut down.
+ if err := srv.Shutdown(shutdownCtx); err != nil {
+ slog.Log(shutdownCtx, slog.LevelError, "HTTP server Shutdown", "error", err)
+ }
+ }()
+
+ if err := srv.Serve(ln); err != nil && !errors.Is(err, http.ErrServerClosed) {
+ return err
+ }
+
+ return nil
+}
+
+func Robot() http.HandlerFunc {
+ robots := `User-agent: *
+Disallow: /
+`
+ return func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Cache-Control", "public, max-age=86400, immutable")
+ w.Header().Set("Content-Type", "text/plain")
+ io.WriteString(w, robots)
+ }
+}