go scratch code for atproto
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}