diff --git a/diffs/my_friendly_container.diff b/diffs/my_friendly_container.diff index 3a24665..96b4d6c 100644 --- a/diffs/my_friendly_container.diff +++ b/diffs/my_friendly_container.diff @@ -1 +1,2 @@ -A /newfile.txt \ No newline at end of file +A /newfile.txt +A /detectme.txt diff --git a/diffs/second_container.diff b/diffs/second_container.diff index 54c37c0..3fddf80 100644 --- a/diffs/second_container.diff +++ b/diffs/second_container.diff @@ -1,5 +1 @@ -D /file1.txt -A /file2.txt -C /do/match/file3.txt -A /dontmatch.yml -D /dont/match.md +A /detectme.yml diff --git a/dist/darwin_amd64_main b/dist/darwin_amd64_main index ffea7da..c38b89c 100755 Binary files a/dist/darwin_amd64_main and b/dist/darwin_amd64_main differ diff --git a/dist/darwin_arm64_main b/dist/darwin_arm64_main index baaea5f..8935d37 100755 Binary files a/dist/darwin_arm64_main and b/dist/darwin_arm64_main differ diff --git a/dist/linux_amd64_main b/dist/linux_amd64_main index 37f63a5..5104047 100755 Binary files a/dist/linux_amd64_main and b/dist/linux_amd64_main differ diff --git a/dist/linux_amd64_main_static b/dist/linux_amd64_main_static index 7aa2b21..a9198e3 100755 Binary files a/dist/linux_amd64_main_static and b/dist/linux_amd64_main_static differ diff --git a/dist/linux_arm64_main b/dist/linux_arm64_main index 66960b5..ebd8cc1 100755 Binary files a/dist/linux_arm64_main and b/dist/linux_arm64_main differ diff --git a/dist/linux_arm64_main_static b/dist/linux_arm64_main_static index 0c6783a..4c16faf 100755 Binary files a/dist/linux_arm64_main_static and b/dist/linux_arm64_main_static differ diff --git a/dist/windows_amd64_main b/dist/windows_amd64_main index d488cd2..4b631dd 100755 Binary files a/dist/windows_amd64_main and b/dist/windows_amd64_main differ diff --git a/main.go b/main.go index 3664535..826fcc8 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,6 @@ package main import ( - "bufio" "crypto/md5" "encoding/json" "fmt" @@ -24,60 +23,100 @@ type ContainerInfo struct { Ignores []string } -var notifiedChanges = struct { - sync.RWMutex - changes map[string]string -}{changes: make(map[string]string)} +type MonitoredContainer struct { + Info ContainerInfo + LastChecked time.Time +} -var apiAddress string +var ( + apiAddress string + glitchtipDSN string + notifiedChanges = make(map[string]string) + monitoredContainers = make(map[string]*MonitoredContainer) + mu sync.Mutex +) func init() { apiAddress = os.Getenv("API_ADDRESS") if apiAddress == "" { apiAddress = "http://localhost:8080" } -} -func main() { - // Check if GLITCHTIP_DSN environment variable is set - glitchtipDSN := os.Getenv("GLITCHTIP_DSN") + glitchtipDSN = os.Getenv("GLITCHTIP_DSN") if glitchtipDSN == "" { log.Fatal("GLITCHTIP_DSN environment variable is not set") } +} +func main() { log.Println("Starting Oculus...") // Ensure the diffs directory exists - err := ensureDiffsDirectory() + err := os.MkdirAll("./diffs", os.ModePerm) if err != nil { log.Fatalf("Error creating diffs directory: %v", err) } for { - containers, err := fetchContainers() + err := fetchAndMonitorContainers() if err != nil { - log.Printf("Error fetching containers: %v", err) - time.Sleep(1 * time.Minute) - continue + log.Printf("Error in fetching and monitoring containers: %v", err) } - var wg sync.WaitGroup - for _, container := range containers { - wg.Add(1) - go func(container ContainerInfo) { - defer wg.Done() - checkAndNotify(container) - }(container) - } - wg.Wait() - - cleanupHashes(containers) - - // Sleep for 1 minute before checking for new containers again - time.Sleep(1 * time.Minute) + time.Sleep(1 * time.Second) } } +func fetchAndMonitorContainers() error { + containers, err := fetchContainers() + if err != nil { + return err + } + + for _, container := range containers { + mu.Lock() + if _, exists := monitoredContainers[container.ID]; !exists { + interval, err := time.ParseDuration(container.Interval) + if err != nil { + log.Printf("Invalid interval for container %s (%s): %v", container.Name, container.ID, err) + mu.Unlock() + continue + } + + monitoredContainers[container.ID] = &MonitoredContainer{ + Info: container, + LastChecked: time.Now().Add(-interval), + } + } + mu.Unlock() + } + + var wg sync.WaitGroup + for _, monitoredContainer := range monitoredContainers { + wg.Add(1) + go func(mc *MonitoredContainer) { + defer wg.Done() + interval, err := time.ParseDuration(mc.Info.Interval) + if err != nil { + log.Printf("Invalid interval for container %s (%s): %v", mc.Info.Name, mc.Info.ID, err) + return + } + + mu.Lock() + if time.Since(mc.LastChecked) >= interval { + mc.LastChecked = time.Now() + mu.Unlock() + checkAndNotify(mc.Info) + } else { + mu.Unlock() + } + }(monitoredContainer) + } + wg.Wait() + + return nil +} + func fetchContainers() ([]ContainerInfo, error) { resp, err := http.Get(fmt.Sprintf("%s/containers", apiAddress)) if err != nil { @@ -134,9 +173,9 @@ func checkAndNotify(container ContainerInfo) { diffHash := fmt.Sprintf("%x", md5.Sum([]byte(filteredOutput))) log.Printf("Diff hash for container %s: %s", container.Name, diffHash) - notifiedChanges.RLock() - lastNotifiedHash, notified := notifiedChanges.changes[container.ID] - notifiedChanges.RUnlock() + mu.Lock() + lastNotifiedHash, notified := notifiedChanges[container.ID] + mu.Unlock() if !notified || lastNotifiedHash != diffHash { filename := filepath.Join("diffs", fmt.Sprintf("%s.diff", container.CName)) @@ -150,9 +189,9 @@ func checkAndNotify(container ContainerInfo) { if err != nil { log.Printf("Error sending notification for container %s: %v", container.ID, err) } else { - notifiedChanges.Lock() - notifiedChanges.changes[container.ID] = diffHash - notifiedChanges.Unlock() + mu.Lock() + notifiedChanges[container.ID] = diffHash + mu.Unlock() log.Printf("Notification sent and hash updated for container: %s (%s)", container.Name, container.ID) } } else { @@ -172,44 +211,25 @@ func filterDiffOutput(diffOutput, cname string, ignores []string) (string, error return "", fmt.Errorf("error writing diff to file: %s", err) } - // Read and filter the diff output - var filteredLines []string - file, err := os.Open(filename) + // Construct the filter command + args := append([]string{filename}, ignores...) + cmd := exec.Command("filter", args...) + fullCommand := fmt.Sprintf("filter %s", strings.Join(cmd.Args, " ")) + log.Printf("Running command: %s", fullCommand) + fmt.Printf("Running command: %s\n", fullCommand) // Print the command to stdout for debugging + + output, err := cmd.CombinedOutput() if err != nil { - return "", fmt.Errorf("error opening diff file: %s", err) - } - defer file.Close() - - scanner := bufio.NewScanner(file) - for scanner.Scan() { - line := scanner.Text() - ignore := false - for _, pattern := range ignores { - match, err := filepath.Match(pattern, line) - if err != nil { - return "", fmt.Errorf("error matching pattern: %s", err) - } - if match { - ignore = true - break - } - } - if !ignore { - filteredLines = append(filteredLines, line) - } + return "", fmt.Errorf("error running filter command: %s, output: %s", err, output) } - if err := scanner.Err(); err != nil { - return "", fmt.Errorf("error reading diff file: %s", err) - } - - filteredOutput := strings.Join(filteredLines, "\n") - err = ioutil.WriteFile(filename, []byte(filteredOutput), 0644) + // Read the filtered output + filteredOutput, err := ioutil.ReadFile(filename) if err != nil { - return "", fmt.Errorf("error writing filtered diff to file: %s", err) + return "", fmt.Errorf("error reading filtered diff file: %s", err) } - return filteredOutput, nil + return string(filteredOutput), nil } func writeToFile(filename, content string) error { @@ -233,23 +253,3 @@ func sendNotification(content string) error { } return nil } - -func ensureDiffsDirectory() error { - return os.MkdirAll("./diffs", os.ModePerm) -} - -func cleanupHashes(containers []ContainerInfo) { - notifiedChanges.Lock() - defer notifiedChanges.Unlock() - - activeContainers := make(map[string]bool) - for _, container := range containers { - activeContainers[container.ID] = true - } - - for id := range notifiedChanges.changes { - if !activeContainers[id] { - delete(notifiedChanges.changes, id) - } - } -}