package server import ( "context" "os" "path/filepath" "slices" "jarl/internal/api" "jarl/internal/stats" ) // storage reports the size of Jarl's databases and how full the disks // Jarl uses are (the dashboard's Storage card). func (s *Server) storage(ctx context.Context) *api.Storage { out := &api.Storage{Databases: []api.Database{}, Disks: []api.Disk{}} dbFile := func(label, path string) *api.Database { if path == "" || path == ":memory:" { return nil } d := api.Database{Label: label, Path: path} for _, suffix := range []string{"", "-wal", "-shm"} { if fi, err := os.Stat(path + suffix); err == nil { d.Bytes += fi.Size() } } out.Databases = append(out.Databases, d) out.Total += d.Bytes return &out.Databases[len(out.Databases)-1] } labels := []string{} dirs := map[string]string{} add := func(label, dir string) { if dir != "" { labels = append(labels, label) dirs[label] = dir } } const jarlDB, statsDB = "Jarl's database", "statistics database" if p := s.store.Path(); p != "" { dbFile(jarlDB, p) add(jarlDB, filepath.Dir(p)) } if s.cfg.Stats != nil { if p := s.cfg.Stats.Store().Path(); p != "" && p != ":memory:" { if d := dbFile(statsDB, p); d != nil && s.cfg.Stats.Options().RetainQueries > 0 { if n, err := s.cfg.Stats.Store().QueryLogSize(ctx); err == nil { d.QueryLogRows = &n } } add(statsDB, filepath.Dir(p)) } if lf := s.cfg.Stats.Options().LogFile; lf != "" { add("named's logs", filepath.Dir(lf)) } } paths := s.eng.Config().Paths add("zone files", paths.ZoneDir) add("named.conf", paths.ConfigDir) add("Jarl's cache and blocklists", paths.CacheDir) add("backups", s.cfg.BackupDir) for _, d := range stats.DiskUsage(labels, dirs) { disk := api.Disk{Path: d.Path, Holds: d.Holds, Total: d.Total, Free: d.Free} for _, db := range out.Databases { if slices.Contains(d.Holds, db.Label) { disk.Databases += db.Bytes } } out.Disks = append(out.Disks, disk) } return out }