summaryrefslogtreecommitdiff
path: root/source/file.go
diff options
context:
space:
mode:
Diffstat (limited to 'source/file.go')
-rw-r--r--source/file.go59
1 files changed, 59 insertions, 0 deletions
diff --git a/source/file.go b/source/file.go
new file mode 100644
index 0000000..4ef0e7c
--- /dev/null
+++ b/source/file.go
@@ -0,0 +1,59 @@
+package source
+
+import (
+ "errors"
+ "fmt"
+ "log/slog"
+ "net/netip"
+ "os"
+)
+
+// a source that reads the address from a file path.
+// useful when your record has to be in-sync with
+// some configured address on your machine.
+type fileSource struct {
+ log *slog.Logger
+ path string
+ family Family
+}
+
+var _ Source = (*fileSource)(nil)
+
+func newFile(log *slog.Logger, cfg Config) (*fileSource, error) {
+ log = log.With(slog.String("source", "file"))
+
+ if _, err := os.Stat(cfg.Path); errors.Is(err, os.ErrNotExist) {
+ return nil, fmt.Errorf("cannot access file for source: %w", err)
+ }
+
+ return &fileSource{log: log, path: cfg.Path, family: cfg.Family}, nil
+}
+
+func (s *fileSource) Supports(f Family) bool { return f == s.family }
+
+func (s *fileSource) Lookup(Family) (netip.Addr, error) {
+ s.log.Info(
+ "will look up address from file source",
+ slog.String("path", s.path),
+ slog.String("family", string(s.family)),
+ )
+
+ raw, err := os.ReadFile(s.path)
+ if err != nil {
+ return netip.Addr{}, fmt.Errorf("file source read failed: %w", err)
+ }
+ content := string(raw)
+
+ addr, err := parse(content, s.family)
+ if err != nil {
+ s.log.Error(
+ "source file does not contain address of expected family",
+ slog.String("path", s.path),
+ slog.String("expected", string(s.family)),
+ slog.String("content", content),
+ )
+ return netip.Addr{}, fmt.Errorf("source file contains bad content: %w", err)
+ }
+
+ return addr, nil
+}