From 41178f6bad1f2e1eaed462475cb7aa26185dc0ac Mon Sep 17 00:00:00 2001 From: Marc Pervaz Boocha Date: Sun, 27 Jul 2025 15:43:06 +0530 Subject: Initial Commit --- main.go | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 main.go (limited to 'main.go') 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) + } +} -- cgit v1.2.3-70-g09d2