package main import ( "bufio" "bytes" "fmt" "log" "os" "os/exec" "path/filepath" "strings" "github.com/fsnotify/fsnotify" ) // TODO flesh out event handling with an eye towards eventual sampling func initHomeWatcher() (*fsnotify.Watcher, error) { fmt.Fprintf(os.Stderr, "setting up home watcher...\n") watcher, err := fsnotify.NewWatcher() if err != nil { return nil, err } out, err := exec.Command("sh", "-c", "stats | jq .active_users[] | tr -d '\"'").Output() if err != nil { return nil, fmt.Errorf("failed to call and process stats: %w", err) } scanner := bufio.NewScanner(bytes.NewReader(out)) for scanner.Scan() { username := strings.TrimSpace(scanner.Text()) home := filepath.Join("/home", username) addHome(watcher, home) } return watcher, nil } func addHome(watcher *fsnotify.Watcher, homePath string) error { fileCount := 0 filepath.Walk(homePath, func(path string, info os.FileInfo, err error) error { if err != nil { return nil } if info.IsDir() && strings.HasPrefix(info.Name(), ".") { return filepath.SkipDir } fileCount++ if info.Mode()&os.ModeSymlink != 0 { return nil } err = watcher.Add(path) if err != nil && err.Error() != "permission denied" && err.Error() != "no such file or directory" { fmt.Printf("%#v\n", err) fmt.Println("Died at ", fileCount) fmt.Printf("%#v\n", info) panic(err.Error()) } else { fmt.Fprintf(os.Stderr, "watching %s\n", path) } return nil }) return nil } func watchHomes(watcher *fsnotify.Watcher) { fmt.Fprintf(os.Stderr, "starting poll\n") for { select { case event, ok := <-watcher.Events: if !ok { return } log.Println("event:", event) if event.Op&fsnotify.Write == fsnotify.Write { log.Println("modified file:", event.Name) } case err, ok := <-watcher.Errors: if !ok { return } log.Println("error:", err) } } } func cli(args []string) int { fmt.Fprintf(os.Stderr, "starting\n") watcher, err := initHomeWatcher() fmt.Fprintf(os.Stderr, "watcher initialized\n") if err != nil { fmt.Fprintf(os.Stderr, "failed to create watcher: %w\n", err) return 1 } defer watcher.Close() // TODO have an event bus to write to // TODO what is this done for do i need this done done := make(chan bool) go watchHomes(watcher) <-done return 0 } func main() { os.Exit(cli(os.Args)) }