go scratch code for atproto
at main 108 lines 2.6 kB view raw
1package main 2 3import ( 4 "context" 5 "log/slog" 6 "net/http" 7 "os" 8 "strings" 9 "time" 10 11 _ "github.com/joho/godotenv/autoload" 12 13 "github.com/bluesky-social/indigo/atproto/syntax" 14 "github.com/hashicorp/golang-lru/v2/expirable" 15 "github.com/urfave/cli/v3" 16) 17 18func main() { 19 if err := run(os.Args); err != nil { 20 slog.Error("exiting", "err", err) 21 os.Exit(-1) 22 } 23} 24 25func run(args []string) error { 26 27 app := cli.Command{ 28 Name: "handlr", 29 Usage: "atproto handle DNS TXT proxy demon", 30 } 31 32 flags := []cli.Flag{ 33 &cli.StringFlag{ 34 Name: "bind", 35 Usage: "local UDP IP and port to listen on. note that DNS port 53 requires superuser on most systems", 36 Value: ":5333", 37 Sources: cli.EnvVars("HANDLR_BIND"), 38 }, 39 &cli.StringFlag{ 40 Name: "backend-host", 41 Usage: "HTTP method, hostname, and port of backend resolution service", 42 Value: "http://localhost:5000", 43 Sources: cli.EnvVars("HANDLR_BACKEND_HOST"), 44 }, 45 &cli.StringFlag{ 46 Name: "domain-suffix", 47 Usage: "domain suffix to filter handles (don't include trailing period)", 48 Sources: cli.EnvVars("HANDLR_DOMAIN_SUFFIX"), 49 }, 50 &cli.IntFlag{ 51 Name: "ttl", 52 Usage: "TTL for both DNS TXT responses, and internal caching", 53 Value: 5 * 60, 54 Sources: cli.EnvVars("HANDLR_TTL"), 55 }, 56 &cli.StringFlag{ 57 Name: "log-level", 58 Usage: "log level (debug, info, warn, error)", 59 Value: "info", 60 Sources: cli.EnvVars("HANDLR_LOG_LEVEL", "LOG_LEVEL"), 61 }, 62 } 63 app.Commands = []*cli.Command{ 64 &cli.Command{ 65 Name: "serve", 66 Usage: "run the handlr daemon", 67 Action: runServe, 68 Flags: flags, 69 }, 70 } 71 return app.Run(context.Background(), args) 72} 73 74func runServe(ctx context.Context, cmd *cli.Command) error { 75 76 logLevel := slog.LevelInfo 77 switch strings.ToLower(cmd.String("log-level")) { 78 case "debug": 79 logLevel = slog.LevelDebug 80 case "info": 81 logLevel = slog.LevelInfo 82 case "warn": 83 logLevel = slog.LevelWarn 84 case "error": 85 logLevel = slog.LevelError 86 } 87 logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ 88 Level: logLevel, 89 AddSource: true, 90 })) 91 slog.SetDefault(logger) 92 93 // set a minimum for the internal cache 94 var cache *expirable.LRU[syntax.Handle, syntax.DID] 95 ttl := cmd.Int("ttl") 96 if ttl != 0 { 97 cache = expirable.NewLRU[syntax.Handle, syntax.DID](10_000, nil, time.Second*time.Duration(ttl)) 98 } 99 client := http.Client{Timeout: time.Second * 5} 100 hr := HTTPResolver{ 101 client: &client, 102 backendHost: cmd.String("backend-host"), 103 suffix: cmd.String("domain-suffix"), 104 ttl: cmd.Int("ttl"), 105 cache: cache, 106 } 107 return hr.Run(cmd.String("bind")) 108}