package mediawire import ( "database/sql" "encoding/json" "fmt" "os" "path/filepath" "strings" _ "modernc.org/sqlite" "gitea.dooplex.hu/admin/felhom-controller/internal/appbackup" "gitea.dooplex.hu/admin/felhom-controller/internal/dockerexec" ) // DockerBox is the production Box: the docker CLI on this guest. type DockerBox struct{} func (DockerBox) Running(c string) bool { out, err := dockerexec.Command("docker", "inspect", "-f", "{{.State.Running}}", c).Output() return err == nil && strings.TrimSpace(string(out)) == "true" } func (DockerBox) Env(c, name string) (string, error) { out, err := dockerexec.Command("docker", "exec", c, "printenv", name).Output() if err != nil { return "", fmt.Errorf("%s: reading %s: %w", c, name, err) } return strings.TrimRight(string(out), "\n"), nil } func (DockerBox) ReadFile(c, path string) ([]byte, error) { out, err := dockerexec.Command("docker", "exec", c, "cat", path).Output() if err != nil { return nil, fmt.Errorf("%s: reading %s: %w", c, path, err) } return out, nil } func (DockerBox) EnsureDir(p string) error { return appbackup.EnsureUserdataDir(p) } func (DockerBox) Mounts(c string) map[string]string { out, err := dockerexec.Command("docker", "inspect", "-f", "{{json .Mounts}}", c).Output() res := map[string]string{} if err != nil { return res } var ms []struct { Source string `json:"Source"` Destination string `json:"Destination"` } if json.Unmarshal(out, &ms) == nil { for _, m := range ms { res[filepath.Clean(m.Destination)] = m.Source } } return res } // JellyfinKey copies Jellyfin's database (with its -wal/-shm, R-286's lesson) into a 0700 temp dir, reads the API key // with this name read-only, and removes the copy at once. The key is returned to the caller only. func (DockerBox) JellyfinKey(name string) (string, error) { dir, err := os.MkdirTemp("", "felhom-jf-") if err != nil { return "", err } defer os.RemoveAll(dir) for _, f := range []string{"jellyfin.db", "jellyfin.db-wal", "jellyfin.db-shm"} { err := dockerexec.Command("docker", "cp", "jellyfin:/config/data/"+f, filepath.Join(dir, f)).Run() if err != nil && f == "jellyfin.db" { return "", fmt.Errorf("copying Jellyfin's database: %w", err) } } db, err := sql.Open("sqlite", "file:"+filepath.Join(dir, "jellyfin.db")) if err != nil { return "", err } defer db.Close() var key string err = db.QueryRow(`SELECT AccessToken FROM ApiKeys WHERE Name = ? ORDER BY DateCreated DESC LIMIT 1`, name).Scan(&key) if err == sql.ErrNoRows { return "", nil } return key, err }