tinyrelayfile
tinyrelay/cmd/tinygit/main.go/

cmd/tinygit/main.go raw
1// Command tinygit serves signed repository metadata and native Git smart HTTP.
2package main
3
4import (
5 "context"
6 "errors"
7 "flag"
8 "fmt"
9 "io"
10 "net"
11 "net/http"
12 "os"
13 "os/exec"
14 "os/signal"
15 "syscall"
16 "time"
17
18 "github.com/FelineStateMachine/tinyrelay/tinygit"
19)
20
21func main() {
22 ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
23 defer stop()
24 if err := run(ctx, os.Args[1:], os.Stdout, os.Stderr); err != nil {
25 fmt.Fprintln(os.Stderr, "tinygit:", err)
26 os.Exit(1)
27 }
28}
29
30func run(ctx context.Context, args []string, stdout, stderr io.Writer) error {
31 flags := flag.NewFlagSet("tinygit", flag.ContinueOnError)
32 flags.SetOutput(stderr)
33 listen := flags.String("listen", "127.0.0.1:8082", "HTTP listen address (put TLS and request limits in front for public hosting)")
34 data := flags.String("data", "./tinygit-data", "dedicated data directory for events.db and bare Git repositories")
35 owner := flags.String("owner", "", "required repository owner's lowercase hex Nostr public key")
36 publicURL := flags.String("public-url", "", "canonical public HTTP(S) URL")
37 if err := flags.Parse(args); err != nil {
38 if errors.Is(err, flag.ErrHelp) {
39 return nil
40 }
41 return err
42 }
43 if flags.NArg() != 0 {
44 return errors.New("unexpected positional arguments")
45 }
46 if _, err := exec.LookPath("git"); err != nil {
47 return fmt.Errorf("native Git is required: %w", err)
48 }
49 handler, err := tinygit.OpenServer(ctx, tinygit.ServerConfig{DataDir: *data, Owner: *owner, PublicURL: *publicURL})
50 if err != nil {
51 return err
52 }
53 defer handler.Close()
54 listener, err := net.Listen("tcp", *listen)
55 if err != nil {
56 return err
57 }
58 defer listener.Close()
59 server := &http.Server{
60 Handler: handler,
61 ReadHeaderTimeout: 10 * time.Second,
62 IdleTimeout: 60 * time.Second,
63 MaxHeaderBytes: 1 << 20,
64 BaseContext: func(net.Listener) context.Context { return ctx },
65 }
66 done := make(chan error, 1)
67 go func() { done <- server.Serve(listener) }()
68 fmt.Fprintln(stdout, "tinygit listening on http://"+listener.Addr().String())
69 select {
70 case err := <-done:
71 if errors.Is(err, http.ErrServerClosed) {
72 return nil
73 }
74 return err
75 case <-ctx.Done():
76 shutdown, cancel := context.WithTimeout(context.Background(), 10*time.Second)
77 defer cancel()
78 err := server.Shutdown(shutdown)
79 if err != nil {
80 _ = server.Close()
81 }
82 serveErr := <-done
83 if errors.Is(serveErr, http.ErrServerClosed) {
84 serveErr = nil
85 }
86 return errors.Join(err, serveErr)
87 }
88}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs