+ New

fierj

Public

Tiny personal git forge

← fierj / main.go
package main

import (
	"context"
	"embed"
	"html/template"
	"log/slog"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

//go:embed templates/*.html
var templateFS embed.FS

func main() {
	cfgPath := "config.json"
	if len(os.Args) > 1 {
		cfgPath = os.Args[1]
	}
	cfg := LoadConfig(cfgPath)

	os.MkdirAll(cfg.Dir, 0755)

	tmpl := template.Must(template.New("").Funcs(funcMap).ParseFS(templateFS, "templates/*.html"))

	mux := http.NewServeMux()

	mux.HandleFunc("GET /", Repos(cfg, tmpl))
	mux.HandleFunc("GET /new", NewRepoGet(tmpl))
	mux.HandleFunc("POST /new", NewRepoPost(cfg, tmpl))
	mux.HandleFunc("GET /{repo}", Tree(cfg, tmpl))
	mux.HandleFunc("GET /{repo}/tree/{ref}/{path...}", Tree(cfg, tmpl))
	mux.HandleFunc("GET /{repo}/blob/{ref}/{path...}", Blob(cfg, tmpl))
	mux.HandleFunc("GET /{repo}/log/{ref}", Log(cfg, tmpl))
	mux.HandleFunc("GET /{repo}/commit/{ref}", Diff(cfg, tmpl))
	mux.HandleFunc("GET /{repo}/refs/", Refs(cfg, tmpl))

	srv := &http.Server{
		Addr:    cfg.Addr,
		Handler: mux,
	}

	// Start SSH server if configured
	if cfg.SSHAddr != "" {
		sshSrv, err := NewSSHServer(cfg.Dir, cfg.SSHHostKey)
		if err != nil {
			slog.Error("failed to create SSH server", "error", err)
			os.Exit(1)
		}
		go func() {
			if err := sshSrv.ListenAndServe(cfg.SSHAddr); err != nil {
				slog.Error("ssh server failed", "error", err)
			}
		}()
	}

	go func() {
		sig := make(chan os.Signal, 1)
		signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
		<-sig
		slog.Info("shutting down...")
		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
		defer cancel()
		srv.Shutdown(ctx)
	}()

	slog.Info("fierj started", "addr", cfg.Addr, "host", cfg.Host, "repos", cfg.Dir)
	if err := srv.ListenAndServe(); err != http.ErrServerClosed {
		slog.Error("failed to start server", "error", err)
	}
	slog.Info("stopped")
}