package monitor import ( "log" "os" "os/exec" "path" "strings" "time" ) type Config struct { ScriptsDir string CacheTimeout time.Duration } type cacheEntry struct { creationTime time.Time output string } type Service struct { Config *Config scriptPaths map[string]string scriptOutputCache map[string]cacheEntry } func NewService(config *Config) *Service { return &Service{ Config: config, scriptPaths: map[string]string{}, scriptOutputCache: map[string]cacheEntry{}, } } func (s *Service) LoadScripts() error { entries, err := os.ReadDir(s.Config.ScriptsDir) if err != nil { return err } s.scriptPaths = map[string]string{} for _, entry := range entries { newScriptPath := path.Join(s.Config.ScriptsDir, entry.Name()) s.scriptPaths[entry.Name()] = newScriptPath } return nil } func (s *Service) InvalidateCache() { log.Printf("Invalidating monitor cache") s.scriptOutputCache = map[string]cacheEntry{} } func (s *Service) GetOutput(command string) (string, error) { // check if output is present in cache if entry, found := s.scriptOutputCache[command]; found { // check if cached value is expired if time.Now().Before(entry.creationTime.Add(s.Config.CacheTimeout)) { log.Printf("Retrieving output of %q from cache", command) return entry.output, nil } } args := strings.Fields(command) log.Printf("Running script %q with args %v", args[0], args[1:]) scriptPath := s.scriptPaths[args[0]] bytes, err := exec.Command(scriptPath, args[1:]...).Output() if err != nil { return "", err } output := string(bytes) log.Printf("Caching output of %q", command) s.scriptOutputCache[command] = cacheEntry{time.Now(), output} return output, nil }