// xdg's Go tools bundle: the account's XDG desktop conventions — its folders, its default // applications and what starts at login. Served by the node's runtime as the operator account. // // None needs the display. Folders, lists and autostart entries are files; xdg-mime and gio answer // from the same files; whether a program runs is read from /proc. Only xdg_default's `set` changes // anything, and only the person's own list of defaults. package main import ( "fmt" "os" stdio "git.novox.be/novox/mesh-sdk/go" ) func main() { if err := stdio.Serve("", tools(NewMachine())); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } func text(args map[string]any, name string) (string, error) { v, ok := args[name] if !ok || v == nil { return "", nil } s, isText := v.(string) if !isText { return "", fmt.Errorf("%s is text", name) } return s, nil } func tools(m *Machine) []stdio.Tool { envArg := map[string]any{"type": "string", "description": "the desktop name dex is given (default: the session's, i3)"} env := func(args map[string]any) (string, error) { e, err := text(args, "environment") if err != nil || e != "" { return e, err } return m.Desktop, nil } return []stdio.Tool{ { Name: "xdg_user_dirs", Description: "The account's folders (Desktop, Downloads, Documents, …) as user-dirs.dirs names them: " + "each one as written, the path it resolves to, whether it exists as a directory, whether it points " + "at the home (not wanted), and the folder xdg-user-dirs would have made instead. Also whether " + "xdg-user-dirs-update may rewrite the file at login, and the locale it was made in.", Run: func(map[string]any) (any, error) { return m.UserDirs(), nil }, }, { Name: "xdg_default", Description: "The default application for a MIME type (text/html) or a URL scheme (https, mailto): what " + "xdg-open uses, what GTK programs use, which mimeapps list decided it, the application's desktop " + "file and whether its program is installed. With set (a desktop file id such as firefox.desktop), " + "make it the default through xdg-mime: it is written to the person's own list, which the mesh " + "never writes and which outranks the mesh's defaults.", Input: map[string]any{ "type": "object", "properties": map[string]any{ "type": map[string]any{"type": "string", "description": "a MIME type (application/pdf) or a URL scheme (https, mailto)"}, "set": map[string]any{"type": "string", "description": "make this installed desktop file id the default (an action)"}, }, "required": []string{"type"}, }, Run: func(args map[string]any) (any, error) { t, err := text(args, "type") if err != nil { return nil, err } mime, err := Normalise(t) if err != nil { return nil, err } set, err := text(args, "set") if err != nil { return nil, err } if set != "" { return m.SetDefault(mime, set) } return m.Handle(mime), nil }, }, { Name: "xdg_open_handlers", Description: "Who opens the links and files that matter (http, https, mailto, HTML, folders, text, " + "Markdown, PDF, images, video, audio, and any types given): the application xdg-open and GTK " + "programs pick and which list decided. Also every mimeapps list in the order applications read " + "them, every default naming an application that is not installed, and every installed handler " + "whose program is missing.", Input: map[string]any{ "type": "object", "properties": map[string]any{ "types": map[string]any{"type": "array", "items": map[string]any{"type": "string"}, "description": "more MIME types or URL schemes to answer for"}, }, }, Run: func(args map[string]any) (any, error) { var extra []string if v, ok := args["types"]; ok && v != nil { list, isList := v.([]any) if !isList { return nil, fmt.Errorf("types is a list of text") } for _, x := range list { s, isText := x.(string) if !isText { return nil, fmt.Errorf("types is a list of text") } extra = append(extra, s) } } return m.OpenHandlers(extra) }, }, { Name: "xdg_autostart", Description: "Every XDG autostart entry, the account's and the system's: what it runs, Hidden, " + "OnlyShowIn and NotShowIn, whether dex starts it at login under the window manager (and if not, " + "why), whether the window manager's own configuration starts the same program too, and how many " + "of the account's processes run it now.", Input: map[string]any{"type": "object", "properties": map[string]any{"environment": envArg}}, Run: func(args map[string]any) (any, error) { e, err := env(args) if err != nil { return nil, err } return map[string]any{"environment": e, "entries": m.Autostarts(e)}, nil }, }, { Name: "xdg_check", Description: "Whether the account's XDG conventions are sound: user-dirs.dirs is the mesh's, every folder " + "it names exists and xdg-user-dirs-update cannot rewrite it; the mesh's default applications are " + "in place, every mimeapps list parses with nothing written twice, no default names an application " + "that is not installed, no handler's program is missing; no program is started twice at login and " + "every program dex starts is installed.", Input: map[string]any{"type": "object", "properties": map[string]any{"environment": envArg}}, Run: func(args map[string]any) (any, error) { e, err := env(args) if err != nil { return nil, err } return m.Check(e), nil }, }, } }